﻿using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using X.Infrastructure.WPF.Extends;

namespace X.WPF.Controls.Helpers
{
    /// <summary>
    /// 文本框帮助类
    /// </summary>
    public class TextBoxHelper
    {
        #region # 字段及构造器

        /// <summary>
        /// 静态构造器
        /// </summary>
        static TextBoxHelper()
        {
            // 注册附加属性
            TextBoxHelper.IsMonitoringProperty = DependencyProperty.RegisterAttached("IsMonitoring", typeof(bool), typeof(TextBoxHelper), new PropertyMetadata(false, TextBoxHelper.IsMonitoringChangedCallback));
            TextBoxHelper.IsSelectAllOnFocusProperty = DependencyProperty.RegisterAttached("IsSelectAllOnFocus", typeof(bool), typeof(TextBoxHelper), new PropertyMetadata(false));
            TextBoxHelper.TextLengthProperty = DependencyProperty.RegisterAttached("TextLength", typeof(int), typeof(TextBoxHelper), new PropertyMetadata(0));
            TextBoxHelper.HasTextProperty = DependencyProperty.RegisterAttached("HasText", typeof(bool), typeof(TextBoxHelper), new PropertyMetadata(false));
            TextBoxHelper.PlaceholderProperty = DependencyProperty.RegisterAttached("Placeholder", typeof(string), typeof(TextBoxHelper), new PropertyMetadata());
            TextBoxHelper.PreFixProperty = DependencyProperty.RegisterAttached("PreFix", typeof(object), typeof(TextBoxHelper), new PropertyMetadata(TextBoxHelper.PreFixChangedCallback));
            TextBoxHelper.SufFixProperty = DependencyProperty.RegisterAttached("SufFix", typeof(object), typeof(TextBoxHelper), new PropertyMetadata(TextBoxHelper.SufFixChangedCallback));
            TextBoxHelper.ShowClearTextButtonProperty = DependencyProperty.RegisterAttached("ShowClearTextButton", typeof(bool), typeof(TextBoxHelper), new PropertyMetadata(true));
            TextBoxHelper.IsClearTextButtonBehaviorEnableProperty = DependencyProperty.RegisterAttached("IsClearTextButtonBehaviorEnable", typeof(bool), typeof(TextBoxHelper), new PropertyMetadata(false, TextBoxHelper.IsClearTextButtonBehaviorEnableChangedCallback));

        }


        /// <summary>
        /// 默认构造器
        /// </summary>
        protected TextBoxHelper()
        {
        }

        #endregion

        #region # 附加属性 

        #region 是否监控 —— string IsMonitoring
        /// <summary>
        /// 是否监控附加属性
        /// </summary>
        public static DependencyProperty IsMonitoringProperty;

        /// <summary>
        /// 获取是否监控
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <returns></returns>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static string GetIsMonitoring(DependencyObject dependencyObject)
        {
            return (string)dependencyObject.GetValue(TextBoxHelper.IsMonitoringProperty);
        }

        /// <summary>
        /// 设置是否监控
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <param name="value"></param>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static void SetIsMonitoring(DependencyObject dependencyObject, string value)
        {
            dependencyObject.SetValue(TextBoxHelper.IsMonitoringProperty, value);
        }
        #endregion

        #region 是否获取焦点时选择全部 —— bool IsSelectAllOnFocus
        /// <summary>
        /// 是否获取焦点时选择全部附加属性
        /// </summary>
        public static DependencyProperty IsSelectAllOnFocusProperty;

        /// <summary>
        /// 获取是否获取焦点时选择全部
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <returns></returns>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static bool GetIsSelectAllOnFocus(DependencyObject dependencyObject)
        {
            return (bool)dependencyObject.GetValue(TextBoxHelper.IsSelectAllOnFocusProperty);
        }

        /// <summary>
        /// 设置是否获取焦点时选择全部
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <param name="value"></param>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static void SetIsSelectAllOnFocus(DependencyObject dependencyObject, bool value)
        {
            dependencyObject.SetValue(TextBoxHelper.IsSelectAllOnFocusProperty, value);
        }
        #endregion

        #region 文本长度 —— int TextLength
        /// <summary>
        /// 文本长度附加属性
        /// </summary>
        public static DependencyProperty TextLengthProperty;

        /// <summary>
        /// 获取文本长度
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <returns></returns>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static int GetTextLength(DependencyObject dependencyObject)
        {
            return (int)dependencyObject.GetValue(TextBoxHelper.TextLengthProperty);
        }

        /// <summary>
        /// 设置文本长度
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <param name="value"></param>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static void SetTextLength(DependencyObject dependencyObject, int value)
        {
            dependencyObject.SetValue(TextBoxHelper.TextLengthProperty, value);
        }
        #endregion

        #region 是否有文本 —— bool HasText
        /// <summary>
        /// 是否有文本附加属性
        /// </summary>
        public static DependencyProperty HasTextProperty;

        /// <summary>
        /// 获取是否有文本
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <returns></returns>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static bool GetHasText(DependencyObject dependencyObject)
        {
            return (bool)dependencyObject.GetValue(TextBoxHelper.HasTextProperty);
        }

        /// <summary>
        /// 设置是否有文本
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <param name="value"></param>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static void SetHasText(DependencyObject dependencyObject, bool value)
        {
            dependencyObject.SetValue(TextBoxHelper.HasTextProperty, value);
        }
        #endregion

        #region 占位符 —— string Placeholder
        /// <summary>
        /// 占位符附加属性
        /// </summary>
        public static DependencyProperty PlaceholderProperty;

        /// <summary>
        /// 获取占位符
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <returns></returns>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static string GetPlaceholder(DependencyObject dependencyObject)
        {
            return (string)dependencyObject.GetValue(TextBoxHelper.PlaceholderProperty);
        }

        /// <summary>
        /// 设置占位符
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <param name="value"></param>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static void SetPlaceholder(DependencyObject dependencyObject, string value)
        {
            dependencyObject.SetValue(TextBoxHelper.PlaceholderProperty, value);
        }

        #endregion

        #region 前缀 —— object PreFix
        /// <summary>
        /// 前缀附加属性
        /// </summary>
        public static DependencyProperty PreFixProperty;

        /// <summary>
        /// 获取前缀
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <returns></returns>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static object GetPreFix(DependencyObject dependencyObject)
        {
            return (object)dependencyObject.GetValue(TextBoxHelper.PreFixProperty);
        }

        /// <summary>
        /// 设置前缀
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <param name="value"></param>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static void SetPreFix(DependencyObject dependencyObject, object value)
        {
            dependencyObject.SetValue(TextBoxHelper.PreFixProperty, value);
        }
        #endregion

        #region 后缀 —— object SufFix
        /// <summary>
        /// 后缀附加属性
        /// </summary>
        public static DependencyProperty SufFixProperty;

        /// <summary>
        /// 获取后缀
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <returns></returns>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static object GetSufFix(DependencyObject dependencyObject)
        {
            return (object)dependencyObject.GetValue(TextBoxHelper.SufFixProperty);
        }

        /// <summary>
        /// 设置后缀
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <param name="value"></param>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static void SetSufFix(DependencyObject dependencyObject, object value)
        {
            dependencyObject.SetValue(TextBoxHelper.SufFixProperty, value);
        }
        #endregion

        #region 清空按钮是否显示 —— bool ShowClearTextButton
        /// <summary>
        /// 清空按钮是否显示附加属性
        /// </summary>
        public static DependencyProperty ShowClearTextButtonProperty;

        /// <summary>
        /// 获取清空按钮是否显示
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <returns></returns>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static bool GetShowClearTextButton(DependencyObject dependencyObject)
        {
            return (bool)dependencyObject.GetValue(TextBoxHelper.ShowClearTextButtonProperty);
        }

        /// <summary>
        /// 设置清空按钮是否显示
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <param name="value"></param>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static void SetShowClearTextButton(DependencyObject dependencyObject, bool value)
        {
            dependencyObject.SetValue(TextBoxHelper.ShowClearTextButtonProperty, value);
        }

        #endregion

        #region 清空按钮行为是否启用 —— bool IsClearTextButtonBehaviorEnable
        /// <summary>
        /// 清空按钮行为是否启用附加属性
        /// </summary>
        public static DependencyProperty IsClearTextButtonBehaviorEnableProperty;

        /// <summary>
        /// 获取清空按钮行为是否启用
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <returns></returns>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static bool GetIsClearTextButtonBehaviorEnable(DependencyObject dependencyObject)
        {
            return (bool)dependencyObject.GetValue(TextBoxHelper.IsClearTextButtonBehaviorEnableProperty);
        }

        /// <summary>
        /// 设置清空按钮行为是否启用
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <param name="value"></param>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static void SetIsClearTextButtonBehaviorEnable(DependencyObject dependencyObject, bool value)
        {
            dependencyObject.SetValue(TextBoxHelper.IsClearTextButtonBehaviorEnableProperty, value);
        }

        #endregion

        #endregion

        #region # 路由事件

        #endregion

        #region # 事件处理程序

        #region 清空按钮点击事件 —— static void ClearTextButtonClick(object sender, RoutedEventArgs eventArgs)
        /// <summary>
        /// 清空按钮点击事件
        /// </summary>
        private static void ClearTextButtonClick(object sender, RoutedEventArgs eventArgs)
        {
            Button button = (Button)sender;

            DependencyObject parent = button.GetAncestors().FirstOrDefault(a => a is RichTextBox || a is TextBox || a is PasswordBox || a is ComboBox);

            if (!TextBoxHelper.GetShowClearTextButton(parent))
                return;


            switch (parent)
            {
                case TextBox textBox:
                    textBox.Clear();
                    textBox.GetBindingExpression(TextBox.TextProperty)?.UpdateSource();
                    break;
                case RichTextBox richTextBox:
                    richTextBox.Document?.Blocks?.Clear();
                    richTextBox.Selection?.Select(richTextBox.CaretPosition, richTextBox.CaretPosition);
                    break;
                case PasswordBox passwordBox:
                    passwordBox.Clear();
                    passwordBox.GetBindingExpression(PasswordBox.PasswordCharProperty)?.UpdateSource();
                    break;
                case ComboBox comboBox:
                    {
                        if (comboBox.IsEditable)
                        {
                            comboBox.Text = string.Empty;
                            comboBox.GetBindingExpression(ComboBox.TextProperty)?.UpdateSource();
                        }

                        comboBox.SelectedItem = null;
                        comboBox.GetBindingExpression(ComboBox.SelectedItemProperty)?.UpdateSource();
                        break;
                    }
            }

        }
        #endregion

        #region 文本框文本改变事件 —— static void TextBoxTextChanged(object sender, RoutedEventArgs eventArgs)
        /// <summary>
        /// 文本框文本改变事件
        /// </summary>
        private static void TextBoxTextChanged(object sender, RoutedEventArgs eventArgs)
        {
            TextBoxHelper.SetTextLength(sender as TextBox, i => i.Text.Length);
        }
        #endregion

        #region 密码框密码改变事件 —— static void PasswordBoxPasswordChanged(object sender, RoutedEventArgs eventArgs)
        /// <summary>
        /// 文本框文本改变事件
        /// </summary>
        private static void PasswordBoxPasswordChanged(object sender, RoutedEventArgs eventArgs)
        {
            TextBoxHelper.SetTextLength(sender as PasswordBox, i => i.Password.Length);
        }
        #endregion

        #region 文本框获取焦点变事件 —— static void TextBoxTextChanged(object sender, RoutedEventArgs eventArgs)
        /// <summary>
        /// 文本框获取焦点变事件
        /// </summary>
        private static void TextBoxGotFocus(object sender, RoutedEventArgs eventArgs)
        {
            TextBoxHelper.GotFocus(sender as TextBoxBase, i => i.SelectAll());
        }
        #endregion

        #region 密码框获取焦点事件 —— static void PasswordBoxGotFocus(object sender, RoutedEventArgs eventArgs)
        /// <summary>
        /// 密码框获取焦点事件
        /// </summary>
        private static void PasswordBoxGotFocus(object sender, RoutedEventArgs eventArgs)
        {
            TextBoxHelper.GotFocus(sender as PasswordBox, i => i.SelectAll());
        }
        #endregion

        #region 组件鼠标左键点击事件 —— static void UiElementPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs eventArgs)
        /// <summary>
        /// 组件鼠标左键点击事件
        /// </summary>
        private static void UiElementPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs eventArgs)
        {
            if (!(sender is UIElement uiElement) || uiElement.IsKeyboardFocusWithin || !TextBoxHelper.GetIsSelectAllOnFocus(uiElement))
                return;

            uiElement.Focus();
            eventArgs.Handled = true;
        }
        #endregion

        #endregion

        #region # 回调方法

        #region 是否监控改变回调方法 —— static void IsMonitoringChangedCallback(DependencyObject dependencyObject...
        /// <summary>
        /// 是否监控改变回调方法
        /// </summary>
        protected static void IsMonitoringChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
        {
            bool newValue = (bool)eventArgs.NewValue;

            switch (dependencyObject)
            {
                case TextBox textBox:

                    if (newValue)
                    {
                        textBox.BeginInvoke(() => TextBoxHelper.TextBoxTextChanged(textBox, new TextChangedEventArgs(TextBoxBase.TextChangedEvent, UndoAction.None)));

                        textBox.TextChanged += TextBoxHelper.TextBoxTextChanged;
                        textBox.GotFocus += TextBoxHelper.TextBoxGotFocus;
                        textBox.PreviewMouseLeftButtonDown += TextBoxHelper.UiElementPreviewMouseLeftButtonDown;
                    }
                    else
                    {
                        textBox.TextChanged -= TextBoxHelper.TextBoxTextChanged;
                        textBox.GotFocus -= TextBoxHelper.TextBoxGotFocus;
                        textBox.PreviewMouseLeftButtonDown -= TextBoxHelper.UiElementPreviewMouseLeftButtonDown;
                    }
                    break;
                case PasswordBox passwordBox:
                    if (newValue)
                    {
                        passwordBox.BeginInvoke(() => TextBoxHelper.PasswordBoxPasswordChanged(passwordBox, new RoutedEventArgs(PasswordBox.PasswordChangedEvent, passwordBox)));

                        passwordBox.PasswordChanged += TextBoxHelper.PasswordBoxPasswordChanged;
                        passwordBox.GotFocus += TextBoxHelper.PasswordBoxGotFocus;
                        passwordBox.PreviewMouseLeftButtonDown += TextBoxHelper.UiElementPreviewMouseLeftButtonDown;
                    }
                    else
                    {
                        passwordBox.PasswordChanged -= TextBoxHelper.PasswordBoxPasswordChanged;
                        passwordBox.GotFocus -= TextBoxHelper.PasswordBoxGotFocus;
                        passwordBox.PreviewMouseLeftButtonDown -= TextBoxHelper.UiElementPreviewMouseLeftButtonDown;
                    }
                    break;
            }
        }
        #endregion

        #region 清空按钮行为可用状态改变回调方法 —— static void IsClearTextButtonBehaviorEnableChangedCallback(DependencyObject dependencyObject...
        /// <summary>
        /// 清空按钮行为可用状态改变回调方法
        /// </summary>
        private static void IsClearTextButtonBehaviorEnableChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
        {
            Button button = (Button)dependencyObject;

            if (eventArgs.OldValue == eventArgs.NewValue || button == null)
                return;

            button.Click -= TextBoxHelper.ClearTextButtonClick;

            if ((bool)eventArgs.NewValue)
            {
                button.Click += TextBoxHelper.ClearTextButtonClick;
            }
        }
        #endregion

        #region 前缀改变回调方法改变回调方法 —— static void PreFixChangedCallback(DependencyObject dependencyObject...
        /// <summary>
        /// 前缀改变回调方法改变回调方法
        /// </summary>

        private static void PreFixChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
        {
        }
        #endregion

        #region 后缀改变回调方法 —— static void SufFixChangedCallback(DependencyObject dependencyObject...
        /// <summary>
        /// 后缀改变回调方法
        /// </summary>
        private static void SufFixChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
        {
        }
        #endregion

        #endregion

        #region # 方法

        #region 设置文本长度 —— static void SetTextLength<T>(T sender...
        /// <summary>
        /// 设置文本长度
        /// </summary>
        private static void SetTextLength<T>(T sender, Func<T, int> getTextLengthFunc) where T : DependencyObject
        {
            if (sender == null)
                return;

            int length = getTextLengthFunc(sender);
            sender.SetValue(TextBoxHelper.TextLengthProperty, length);
            sender.SetValue(TextBoxHelper.HasTextProperty, length > 0);
        }
        #endregion

        #region 获取焦点 —— static void GotFocus<T>(T sender, Action<T> action)
        /// <summary>
        /// 获取焦点
        /// </summary>
        private static void GotFocus<T>(T sender, Action<T> action) where T : DependencyObject
        {
            if (sender == null)
                return;

            bool isSelectAllOnFocus = TextBoxHelper.GetIsSelectAllOnFocus(sender);
            if (!isSelectAllOnFocus)
                return;

            sender.Dispatcher.BeginInvoke(action, sender);
        }
        #endregion

        #endregion
    }
}